home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / shanghai.000 / shanghai / shanghai-1.0 / board.c next >
C/C++ Source or Header  |  1995-05-29  |  21KB  |  643 lines

  1. #include <memory.h>
  2. #include <stdarg.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <sys/time.h>
  7.  
  8. #include "board.h"
  9. #include "forms.h"
  10. #include "game.h"
  11. #include "gui.h"
  12. #include "mapdata.h"
  13. #include "shanghai.h"
  14.  
  15. static XColor icon_colors[16];
  16. static GC     gc_mask;
  17. static GC     gc_tile;
  18. static GC     gc_copy;
  19. static Pixmap scrap;
  20. static Pixmap icons;
  21. static Pixmap mask;
  22. static Pixmap shadow_top;
  23. static Pixmap shadow_right;
  24. static Pixmap status_pixmap;
  25. static Pixmap status_mask;
  26.  
  27. static FL_RAW_CALLBACK rawcallback;
  28.  
  29. #ifndef __GNUC__
  30. int intersect(int  x1,int  y1,int  w1,int  h1,
  31.           int  x2,int  y2,int  w2,int  h2,
  32.           int *x3,int *y3,int *w3,int *h3)
  33. {
  34.   *x3 = max(x1,x2);
  35.   *y3 = max(y1,y2);
  36.   *w3 = min(x1+w1-1,x2+w2-1) - *x3 + 1;
  37.   *h3 = min(y1+h1-1,y2+h2-1) - *y3 + 1;
  38.   return((*w3 > 0) && (*h3 > 0));
  39. }
  40. #endif
  41.  
  42. static void initialize_colors(void)
  43. {
  44.   int vmode;
  45.   int depth;
  46.   Display *disp;
  47.   Colormap colormap;
  48.   int col;
  49.  
  50.   vmode = fl_get_vclass();
  51.   depth = fl_state[vmode].depth;
  52.   disp = fl_get_display();
  53.   colormap = fl_state[vmode].colormap;
  54.   for (col = 0; col < 16; col++)
  55.     if (!XAllocNamedColor(disp,colormap,
  56.               (depth < 4 ? mono_col_names :
  57.                depth== 4 ? simple_col_names : col_names)[col],
  58.               icon_colors+col,icon_colors+col)) {
  59.       fprintf(stderr,"Could not allocate color \"%s\"\n",
  60.           col_names[col]);
  61.       exit(1); }
  62.   return;
  63. }
  64.  
  65. static void initialize_gc(void)
  66. {
  67.   Display *disp;
  68.   int     screen;
  69.   Window  win;
  70.  
  71.   disp = fl_get_display();
  72.   screen = fl_screen;
  73.   win = RootWindow(disp,screen);
  74.   gc_mask = XCreateGC(disp,win,0,NULL);
  75.   XSetGraphicsExposures(disp,gc_mask,False);
  76.   XSetForeground(disp,gc_mask,0);
  77.   XSetBackground(disp,gc_mask,~0);
  78.   XSetFunction(disp,gc_mask,GXand);
  79.   gc_tile = XCreateGC(disp,win,0,NULL);
  80.   XSetGraphicsExposures(disp,gc_tile,False);
  81.   XSetForeground(disp,gc_tile,icon_colors[15].pixel);
  82.   XSetBackground(disp,gc_tile,0);
  83.   XSetFunction(disp,gc_tile,GXor);
  84.   gc_copy = XCreateGC(disp,win,0,NULL);
  85.   XSetFunction(disp,gc_copy,GXcopy);
  86.   XSetForeground(disp,gc_copy,fl_get_flcolor(FL_COL1));
  87.   XSetBackground(disp,gc_copy,BlackPixel(disp,screen));
  88.   return;
  89. }
  90.  
  91. static Pixmap convert_pixmap(int isselectable,unsigned char *data,
  92.                  int width,int height,int *col_conv,
  93.                  int *dither)
  94. {
  95.   int           vmode;
  96.   int           depth;
  97.   Display       *disp;
  98.   int           screen;
  99.   Window        win;
  100.   GC            gc;
  101.   Pixmap        bitmap,dest;
  102.   unsigned long pixel;
  103.   unsigned char *plane_bits,*sptr,*dptr,dithermask[4];
  104.   int           col,hcol,rep,x,y,bit;
  105.  
  106.   vmode = fl_get_vclass();
  107.   depth = fl_state[vmode].depth;
  108.   disp = fl_get_display();
  109.   screen = fl_screen;
  110.   win = RootWindow(disp,screen);
  111.   if ((plane_bits = malloc((((width+7)&~7)*height)/8)) == NULL) {
  112.     fprintf(stderr,"Out of memory\n");
  113.     exit(1); }
  114.   if ((dest = XCreatePixmap(disp,win,width,
  115.                 isselectable?2*height:height,depth)) == 0) {
  116.     fprintf(stderr,"Could not allocate icon pixmap\n");
  117.     exit(1); }
  118.   gc = XCreateGC(disp,win,0,NULL);
  119.   XSetGraphicsExposures(disp,gc,False);
  120.   XSetForeground(disp,gc,0);
  121.   XSetBackground(disp,gc,0);
  122.   XFillRectangle(disp,dest,gc,0,0,width,isselectable?2*height:height);
  123.   XSetFunction(disp,gc,GXor);
  124.   memset(dithermask,0xFF,sizeof(dithermask));
  125.   for (col = 1; (hcol = col*16), col < 16; col++) {
  126.     if (dither) {
  127.       memset(dithermask,0,sizeof(dithermask));
  128.       for (x = 0; x < 16; x++)
  129.     if (col != 7 && dither[x] <= luminance[(8+col%8)|1])
  130.       dithermask[x/4] |= (0x01 << (x%4)) | (0x10 << (x%4)); }
  131.     for (rep = dither ? 1 : 0; rep >= 0; rep--) {
  132.       memset(plane_bits,0,(((width+7)&~7)*height)/8);
  133.       for (sptr = data, dptr = plane_bits, y=0; y < height; y++) {
  134.     for (x = 0, bit = 0x1; x < width; x += 2) {
  135.       if ((*sptr & 0xF0) == hcol)
  136.         *dptr |= bit;
  137.       bit <<= 1;
  138.       if ((*sptr++ & 0x0F) == col)
  139.         *dptr |= bit;
  140.       if ((bit <<= 1) == 0x100) {
  141.         *dptr++ &= dithermask[y%4];
  142.         bit = 0x1; } }
  143.     if (bit != 0x1)
  144.       *dptr++ &= dithermask[y%4]; }
  145.       if ((bitmap = XCreateBitmapFromData(disp,win,plane_bits,
  146.                       width,height)) == 0) {
  147.     fprintf(stderr,"Out of server memory\n");
  148.     exit(1); }
  149.       pixel = icon_colors[col_conv[col]].pixel;
  150.       if (rep)
  151.     pixel = pixel == icon_colors[0].pixel ?
  152.             icon_colors[15].pixel : icon_colors[0].pixel;
  153.       XSetForeground(disp,gc,pixel);
  154.       XCopyPlane(disp,bitmap,dest,gc,0,0,width,height,0,0,1);
  155.       if (isselectable) {
  156.     if (depth >= 4) {
  157.       if (col == 7 || col == 8)
  158.         XSetForeground(disp,gc,icon_colors[col == 7 ? 8 : 7].pixel); }
  159.     else {
  160.       pixel = pixel == icon_colors[0].pixel ?
  161.               icon_colors[15].pixel : icon_colors[0].pixel;
  162.       XSetForeground(disp,gc,pixel); }
  163.     XCopyPlane(disp,bitmap,dest,gc,0,0,width,height,0,height,1); }
  164.       XFreePixmap(disp,bitmap); 
  165.       if (rep)
  166.     for (x = 4; x--;) dithermask[x] ^= 0xFF; } }
  167.   XFreeGC(disp,gc);
  168.   free(plane_bits);
  169.   return(dest);
  170. }
  171.  
  172. static void initialize_pixmap(void)
  173. {
  174.   int     vmode;
  175.   int     depth;
  176.   Display *disp;
  177.   int     screen;
  178.   Window  win;
  179.  
  180.   vmode = fl_get_vclass();
  181.   depth = fl_state[vmode].depth;
  182.   disp = fl_get_display();
  183.   screen = fl_screen;
  184.   win = RootWindow(disp,screen);
  185.   if ((scrap = XCreatePixmap(disp,win,
  186.                  (ICON_WIDTH-DIM3DX-1)*15+DIM3DX+SHADOWX+1,
  187.                  (ICON_HEIGHT-DIM3DY-1)*8+DIM3DY+SHADOWY+1,
  188.                  depth)) == 0) {
  189.     fprintf(stderr,"Could not allocate scrap pixmap\n");
  190.     exit(1); }
  191.   icons = convert_pixmap(1,icons_data,ICON_WIDTH*ICON_COUNT,ICON_HEIGHT,
  192.              no_col_conv,depth < 4 ? dither_matrix : NULL);
  193.   status_pixmap = convert_pixmap(0,status_data,STATUS_WIDTH,
  194.                  STATUS_HEIGHT*STATUS_COUNT,
  195.                  depth < 4 ? status_col_conv : no_col_conv,
  196.                  NULL);
  197.   if ((mask = XCreateBitmapFromData(disp,win,mask_bits,ICON_WIDTH,
  198.                     ICON_HEIGHT)) == 0) {
  199.     fprintf(stderr,"Out of server memory\n");
  200.     exit(1); }
  201.   if ((status_mask = XCreateBitmapFromData(disp,win,status_mask_bits,
  202.                        STATUS_WIDTH,
  203.                        STATUS_HEIGHT*STATUS_COUNT)) == 0) {
  204.     fprintf(stderr,"Out of server memory\n");
  205.     exit(1); }
  206.   if ((shadow_top = XCreateBitmapFromData(disp,win,top_bits,TOP_WIDTHS,
  207.                       TOP_HEIGHTS)) == 0) {
  208.     fprintf(stderr,"Out of server memory\n");
  209.     exit(1); }
  210.   if ((shadow_right = XCreateBitmapFromData(disp,win,right_bits,RIGHT_WIDTHS,
  211.                         RIGHT_HEIGHTS)) == 0) {
  212.     fprintf(stderr,"Out of server memory\n");
  213.     exit(1); }
  214.   return;
  215. }
  216.  
  217. static void initialize_board(void)
  218. {
  219.   static int initialized = 0;
  220.  
  221.   if (initialized)
  222.     return;
  223.   initialized = 1;
  224.   initialize_colors();
  225.   initialize_gc();
  226.   initialize_pixmap();
  227.   return;
  228. }
  229.  
  230. #ifndef __GNUC__
  231. void tile_pos(int pos,int *x,int *y,int *w,int *h,
  232.           int *ox,int *oy,int *ow,int *oh)
  233. {
  234.   int   ix,iy;
  235.  
  236.   ix = (board[pos].x*(ICON_WIDTH-DIM3DX-1))/2  + DIM3DX*board[pos].depth;
  237.   iy = (board[pos].y*(ICON_HEIGHT-DIM3DY-1))/2 - DIM3DY*board[pos].depth;
  238.   if ( x)  *x = ix+DIM3DX;
  239.   if ( y)  *y = iy+SHADOWY;
  240.   if ( w)  *w = ICON_WIDTH-DIM3DX;
  241.   if ( h)  *h = ICON_HEIGHT-DIM3DY;
  242.   if (ox) *ox = ix;
  243.   if (oy) *oy = iy;
  244.   if (ow) *ow = ICON_WIDTH+SHADOWX;
  245.   if (oh) *oh = ICON_HEIGHT+SHADOWY;
  246.   return;
  247. }
  248. #endif
  249.  
  250. static void draw_tile(Display *disp,Drawable dst,int pos,int selected,
  251.               unsigned char *occ)
  252. {
  253.   int   ix,iy,iw,ih,ox,oy,i,icon;
  254.  
  255.   if ((icon = occ[pos]) == NIL)
  256.     return;
  257.   icon = ((icon < 4*(3*9+7)) ? icon/4 : icon - (4-1)*(3*9+7))*ICON_WIDTH;
  258.   tile_pos(pos,&ix,&iy,&iw,&ih,&ox,&oy,0,0);
  259.   if ((i = board[pos].shd0) == NIL || occ[i] == NIL) {
  260.     if ((i = board[pos].shd1) != NIL && occ[i] != NIL) {
  261.       XCopyPlane(disp,shadow_top,dst,gc_mask,ICSTOP,ix,oy,1);
  262.       XCopyPlane(disp,shadow_top,dst,gc_tile,ICSTOP,ix,oy,1); }
  263.     else {
  264.       XCopyPlane(disp,shadow_top,dst,gc_mask,ICTOP, ix,oy,1);
  265.       XCopyPlane(disp,shadow_top,dst,gc_tile,ICTOP, ix,oy,1); } }
  266.   if ((pos ==   3 && occ[  1] != NIL) ||
  267.       (pos == 143 && occ[140] == NIL && occ[141] != NIL)) {
  268.     XCopyPlane(disp,shadow_right,dst,gc_mask,ICHHIGH,ix+iw,oy+1,1);
  269.     XCopyPlane(disp,shadow_right,dst,gc_tile,ICHHIGH,ix+iw,oy+1,1); }
  270.   else if ((pos == 4 && occ[1] != NIL) ||
  271.        (pos == 143 && occ[140] != NIL && occ[141] == NIL)) {
  272.     XCopyPlane(disp,shadow_right,dst,gc_mask,ICHLOW,ix+iw,
  273.            iy+(ICON_HEIGHT-DIM3DY)/2+1,1);
  274.     XCopyPlane(disp,shadow_right,dst,gc_tile,ICHLOW,ix+iw,
  275.            iy+(ICON_HEIGHT-DIM3DY)/2+1,1);}
  276.   else if ((i = board[pos].right[0]) == NIL || occ[i] == NIL) {
  277.     if ((i = board[pos].shd1) != NIL && occ[i] != NIL) {
  278.       XCopyPlane(disp,shadow_right,dst,gc_mask,ICSRIGHT,ix+iw,oy+1,1);
  279.       XCopyPlane(disp,shadow_right,dst,gc_tile,ICSRIGHT,ix+iw,oy+1,1); }
  280.     else {
  281.       XCopyPlane(disp,shadow_right,dst,gc_mask,ICRIGHT,ix+iw,oy+1,1);
  282.       XCopyPlane(disp,shadow_right,dst,gc_tile,ICRIGHT,ix+iw,oy+1,1); } }
  283.   XCopyPlane(disp,mask,dst,gc_mask,0,0,ICON_WIDTH,ICON_HEIGHT,ox,iy,1);
  284.   XCopyArea(disp,icons,dst,gc_tile,icon,0,ICON_WIDTH,ICON_HEIGHT,ox,iy);
  285.   if (selected) {
  286.     XCopyPlane(disp,mask,dst,gc_mask,ix-ox+1,1,iw-2,ih-2,ix+1,iy+1,1);
  287.     XCopyArea(disp,icons,dst,gc_tile,icon+(ix-ox)+1,ICON_HEIGHT+1,
  288.           iw-2,ih-2,ix+1,iy+1); }
  289.   return;
  290. }
  291.  
  292. void draw_area(int x,int y,int w,int h,BoardRec *board_rec)
  293. {
  294.   Display       *disp = board_rec->disp;
  295.   Drawable      win   = board_rec->win;
  296.   unsigned char *occ  = board_rec->occ;
  297.   int   i,j,ox,oy,ow,oh,ix,iy,iw,ih,depth = -1;
  298.  
  299.   if (board_rec->paused)
  300.     return;
  301.   XFillRectangle(disp,scrap,gc_copy,x,y,w,h);
  302.   /* GNU C's inline optimization simplifies this code a lot! */
  303.   tile_pos(0,0,0,&iw,&ih,0,0,&ow,&oh);
  304.   if (w == iw && h == ih) for (i = 0; i < 144; i++) {
  305.     tile_pos(i,&ix,&iy,0,0,0,0,0,0);
  306.     if (x == ix && y == iy) { depth = board[i].depth; break; } }
  307.   else if (w == ow && h == oh) for (i = 0; i < 144; i++) {
  308.     tile_pos(i,0,0,0,0,&ox,&oy,0,0);
  309.     if (x == ox && y == oy) { depth = board[i].depth-1; break; } }
  310.   for (i = 0; i < 144; i++)
  311.     if (occ[i] != NIL &&
  312.     ((j = board[i].top) == NIL || occ[j] == NIL ||
  313.      board[i].depth >= depth)) {
  314.       tile_pos(i,0,0,0,0,&ox,&oy,&ow,&oh);
  315.       if (intersect(x,y,w,h,ox,oy,ow,oh,&ox,&oy,&ow,&oh))
  316.     draw_tile(disp,scrap,i,i == board_rec->sel0 ||
  317.           i == board_rec->sel1 || board_rec->inverted[i] != NIL,occ); }
  318.   XCopyArea(disp,scrap,win,gc_copy,x,y,w,h,board_rec->ox+x,board_rec->oy+y);
  319.   return;
  320. }
  321.  
  322. void draw_all_tiles(BoardRec *board_rec)
  323. {
  324.   FL_OBJECT * const board_frame = board_rec->board->board_frame;
  325.   FL_OBJECT * const status_box  = board_rec->board->status_box;
  326.  
  327.   /* this is a dirty hack, but prevents flicker */
  328.   draw_area(0,0,status_box->x-board_frame->x,board_frame->h,board_rec);
  329.   draw_area(status_box->x-board_frame->x,
  330.         status_box->y+status_box->h-board_frame->y,
  331.         board_frame->x+board_frame->w-status_box->x,
  332.         board_frame->y+board_frame->h-status_box->y-status_box->h,
  333.         board_rec);
  334.   return;
  335. }
  336.  
  337. static int focus_out(FL_FORM *board,void *ev)
  338. {
  339.   /* XForms does not support tracking of focus, so we will only get
  340.      LeaveNotify events; besides, it it often hard to differentiate
  341.      between leaving the main window and leaving popup menus;
  342.      this code fails to detect focus changes that are not accompanied
  343.      by moving the pointer out of the main window!
  344.      hopefully this will be fixed some day */
  345.   BoardRec * const board_rec = board->u_vdata;
  346.   XEvent   * const event     = ev;
  347.   int              xr,yr,x,y;
  348.   unsigned int     mask;
  349.   Window           root,child = None;
  350.  
  351.   if (event->type == FocusOut ||
  352.       (event->type == LeaveNotify &&
  353.        ((event->xcrossing.mode == NotifyNormal &&
  354.      (event->xcrossing.detail == NotifyNonlinear ||
  355.       event->xcrossing.detail == NotifyAncestor) &&
  356.      (event->xcrossing.x < 0 || event->xcrossing.x >= board->w ||
  357.       event->xcrossing.y < 0 || event->xcrossing.y >= board->h)) ||
  358.     !XQueryPointer(board_rec->disp,board_rec->win,&root,&child,
  359.                &xr,&yr,&x,&y,&mask) ||
  360.     x < 0 || x >= board->w || y < 0 || y >= board->h))) {
  361.     if (board_rec->time > 0) {
  362.       board_rec->paused = 1;
  363.       fl_show_object(board_rec->board->pausebox);
  364.       if ((board_rec->time -= time(0)) == 0)
  365.     board_rec->time = -1;
  366.       update_info_box(board_rec); } }
  367.   return(0);
  368. }
  369.  
  370. static __inline__ long long timediff(struct timeval *tv1,struct timeval *tv2)
  371. {
  372.   return(tv1->tv_usec - tv2->tv_usec + (tv1->tv_sec-tv2->tv_sec)*1000000LL);
  373. }
  374.  
  375. static void handle_step(BoardRec *board_rec)
  376. {
  377.   static long long const limit1 = 150000;
  378.   static long long       loops = 1;
  379.   long long              i,l;
  380.   struct timeval         tv1,tv2;
  381.   int                    j;
  382.  
  383.   for (j = 10; j--;) {
  384.     gettimeofday(&tv1,NULL);
  385.     if (board_rec->time > 0 && timediff(&tv1,&board_rec->tv) > 200000) {
  386.       update_info_box(board_rec);
  387.       gettimeofday(&board_rec->tv,NULL); }
  388.     for (i = loops; i--;)
  389.       if (depth_scan(board_rec) != dsBusy)
  390.     return;
  391.     gettimeofday(&tv2,NULL);
  392.     if ((l = timediff(&tv2,&tv1)) <= 0 ||
  393.     (l = (loops*limit1)/l) <= 0) loops = 1;
  394.     else if (l > loops)
  395.       if (10*l > 11*loops) loops = (11*(loops+1))/10; else loops = l;
  396.     else loops = l;
  397.     if (XPending(board_rec->disp))
  398.       break; }
  399.   return;
  400. }
  401.  
  402. static int board_handle_free(FL_OBJECT *ob,int event,FL_Coord mx,FL_Coord my,
  403.                  int key,void *xev)
  404. {
  405.   BoardRec *board_rec = (BoardRec *)ob->u_vdata;
  406.  
  407.   if (event == FL_DRAW || event == FL_PUSH || event == FL_STEP) {
  408.     if (board_rec->disp == NULL) {
  409.       board_rec->disp = fl_get_display();
  410.       board_rec->win  = FL_ObjWin(ob);
  411.       initialize_board(); } }
  412.   switch (event) {
  413.   case FL_DRAW:
  414.     if (!board_rec->paused)
  415.       draw_area(0,0,ob->w,ob->h,board_rec);
  416.     break;
  417.   case FL_PUSH:
  418.     if (!board_rec->paused)
  419.       handle_mouse_push(mx - ob->x,my - ob->y,key,board_rec);
  420.     break;
  421.   case FL_STEP:
  422.     handle_step(board_rec);
  423.   default:
  424.     break; }
  425.   return(0);
  426. }
  427.  
  428. void board_callback(FL_OBJECT *ob,long data)
  429. {
  430.   FD_board  * const fd_board    = (FD_board *)data;
  431.   FL_OBJECT * const board_frame = fd_board->board_frame;
  432.   XEvent            *event;
  433.  
  434.   event = (XEvent *)fl_last_event();
  435.   if (event->type == ButtonPress)
  436.     board_handle_free(board_frame,FL_PUSH,event->xbutton.x,event->xbutton.y,
  437.               event->xbutton.button,event);
  438.   return;
  439. }
  440.  
  441. static int lsprintf(FL_OBJECT *ob,const char *s,...)
  442.      __attribute__((format(printf,2,3)));
  443. static int lsprintf(FL_OBJECT *ob,const char *s,...)
  444. {
  445.   static char buffer[80];
  446.   va_list     arg;
  447.   int         rc;
  448.  
  449.   va_start(arg,s);
  450.   rc = vsprintf(buffer,s,arg);
  451.   fl_set_object_label(ob,buffer);
  452.   va_end(arg);
  453.   return(rc);
  454. }
  455.  
  456. void update_info_box(BoardRec *board_rec)
  457. {
  458.   InfoBoxRec infobox_rec;
  459.   time_t     secs;
  460.   
  461.   infobox_rec.seed       = board_rec->seed;
  462.   infobox_rec.remain     = board_rec->remain;
  463.   infobox_rec.matchcount = board_rec->matchcount;
  464.   secs = board_rec->time > 0 ? time(0) - board_rec->time :
  465.          board_rec->time < 0 ?         - board_rec->time : 0;
  466.   if (secs < 3600) {
  467.     infobox_rec.time0    = (int)(secs/60);
  468.     infobox_rec.time1    = 0;
  469.     infobox_rec.time2    = (int)(secs%60); }
  470.   else if (secs < 360000) {
  471.     infobox_rec.time0    = (int)(secs/3600);
  472.     infobox_rec.time1    = 1;
  473.     infobox_rec.time2    = (int)(secs%3600)/60; }
  474.   else {
  475.     infobox_rec.time0    = 0;
  476.     infobox_rec.time1    = 2;
  477.     infobox_rec.time2    = 0; }
  478.   infobox_rec.rank       = board_rec->rank;
  479.   infobox_rec.scoremode  = board_rec->scoremode;
  480.   infobox_rec.status     = board_rec->depthscan.status;
  481.   if (memcmp(&infobox_rec,&board_rec->infobox,sizeof(InfoBoxRec))) {
  482.     fl_freeze_form(board_rec->board->board);
  483.     if (!board_rec->paused) {
  484.       if (infobox_rec.seed != board_rec->infobox.seed) {
  485.     char buffer[12];
  486.     sprintf(buffer,"%09d",infobox_rec.seed);
  487.     fl_set_input(board_rec->board->inp_board_num,buffer); }
  488.       if (infobox_rec.remain != board_rec->infobox.remain)
  489.     lsprintf(board_rec->board->remain,"Remain: %d",infobox_rec.remain);
  490.       if (infobox_rec.matchcount != board_rec->infobox.matchcount)
  491.     lsprintf(board_rec->board->match,"Match: %d",infobox_rec.matchcount);
  492.       if (infobox_rec.time0 != board_rec->infobox.time0 ||
  493.       infobox_rec.time1 != board_rec->infobox.time1 ||
  494.       infobox_rec.time2 != board_rec->infobox.time2)
  495.     lsprintf(board_rec->board->time,infobox_rec.time1 == 2 ?
  496.          "Time ???" : "Time %2d%c%02d",infobox_rec.time0,
  497.          infobox_rec.time1?'h':':',infobox_rec.time2);
  498.       if (infobox_rec.rank != board_rec->infobox.rank)
  499.     lsprintf(board_rec->board->rank,infobox_rec.rank ?
  500.          "Rank #%d":"No rank",infobox_rec.rank);
  501.       if (infobox_rec.scoremode != board_rec->infobox.scoremode)
  502.     lsprintf(board_rec->board->scoremode,"%sScoring",
  503.          infobox_rec.scoremode?"":"Non-"); }
  504.     if (infobox_rec.status != board_rec->infobox.status)
  505.       fl_redraw_object(board_rec->board->status);
  506.     fl_unfreeze_form(board_rec->board->board);
  507.     if (board_rec->paused)
  508.       board_rec->infobox.status = infobox_rec.status;
  509.     else
  510.       board_rec->infobox = infobox_rec; }
  511.   fl_set_menu_item_mode(board_rec->board->file,2,board_rec->time == 0 ?
  512.             FL_PUP_GREY : FL_PUP_NONE);
  513.   fl_set_menu_item_mode(board_rec->board->options,1,infobox_rec.remain == 144 ?
  514.             FL_PUP_GREY : FL_PUP_NONE);
  515.   fl_set_menu_item_mode(board_rec->board->options,2,(!board_rec->time ||
  516.             !board_rec->matchcount ? FL_PUP_GREY : FL_PUP_NONE) |
  517.             (board_rec->paused ? FL_PUP_CHECK : FL_PUP_BOX));
  518.   fl_set_menu_item_mode(board_rec->board->options,3,board_rec->isfastgame ?
  519.             FL_PUP_CHECK : FL_PUP_BOX);
  520.   return;
  521. }
  522.  
  523. static int status_handle_free(FL_OBJECT *ob,int event,FL_Coord mx,FL_Coord my,
  524.                   int key,void *xev)
  525. {
  526.   BoardRec *board_rec = (BoardRec *)ob->u_vdata;
  527.  
  528.   if (event == FL_DRAW || event == FL_PUSH) {
  529.     if (board_rec->disp == NULL) {
  530.       board_rec->disp = fl_get_display();
  531.       board_rec->win  = FL_ObjWin(ob);
  532.       initialize_board(); } }
  533.   switch (event) {
  534.   case FL_DRAW: {
  535.     Display * const disp = board_rec->disp;
  536.     Drawable const  win  = board_rec->win;
  537.     enum dsStatus status = board_rec->depthscan.status;
  538.     XFillRectangle(disp,win,gc_copy,ob->x,ob->y,ob->w,ob->h);
  539.     XCopyPlane(disp,status_mask,win,gc_mask,0,STATUS_HEIGHT*(status-dsBusy),
  540.            STATUS_WIDTH,STATUS_HEIGHT,ob->x,ob->y,1);
  541.     XCopyArea(disp,status_pixmap,win,gc_tile,0,STATUS_HEIGHT*(status-dsBusy),
  542.           STATUS_WIDTH,STATUS_HEIGHT,ob->x,ob->y);
  543.     break; }
  544.   case FL_PUSH:
  545.     if (!board_rec->paused)
  546.       handle_status_push(key,board_rec);
  547.     break;
  548.   default:
  549.     break; }
  550.   return(0);
  551. }
  552.  
  553. void board_inp_board_num(FL_OBJECT *ob, long data)
  554. {
  555.   FD_board *fd_board = (FD_board *)data;
  556.   BoardRec *board_rec = (BoardRec *)fd_board->board_frame->u_vdata;
  557.  
  558.   if (board_rec->boardnumeditable)
  559.     deactivate_board_num(board_rec);
  560.   else {
  561.     board_rec->boardnumeditable = 1;
  562.     fl_activate_object(fd_board->inp_board_num);
  563.     fl_set_object_focus(fd_board->board,fd_board->inp_board_num); }
  564.   return;
  565. }
  566.  
  567. void deactivate_board_num(BoardRec *board_rec)
  568. {
  569.   int      seed;
  570.  
  571.   if (board_rec->boardnumeditable) {
  572.     board_rec->boardnumeditable = 0;
  573.     fl_deactivate_object(board_rec->board->inp_board_num);
  574.     fl_set_object_focus(board_rec->board->board,NULL);
  575.     seed = atoi(fl_get_input(board_rec->board->inp_board_num));
  576.     if (seed != board_rec->seed) {
  577.       FD_board *fd_board = board_rec->board;
  578.       default_isfastgame = board_rec->isfastgame;
  579.       if (!seed) {
  580.     free(board_rec); board_rec = NULL;
  581.     srand(time(0)); do {seed = rand();} while (seed == 0); }
  582.       board_rec = initialize_board_rec(fd_board,board_rec,seed);
  583.       draw_all_tiles(board_rec); } }
  584.   return;
  585. }
  586.  
  587. static int board_close(FL_FORM *board,void *ptr)
  588. {
  589.   free(board->u_vdata);
  590.   fl_hide_form(board);
  591.   fl_free_form(board);
  592.   if (--win_count == 0)
  593.     exit(0);
  594.   return(FL_IGNORE);
  595. }
  596.  
  597. static void fl_xset_menu(FL_OBJECT *ob,char *m,...)
  598. {
  599.   int     i = 0;
  600.   va_list arg_ptr;
  601.   char    *s;
  602.  
  603.   fl_set_menu(ob,m);
  604.   for (va_start(arg_ptr,m); (s = va_arg(arg_ptr,char *)) != NULL; )
  605.     fl_set_menu_item_shortcut(ob,++i,s);
  606.   return;
  607. }
  608.  
  609. FD_board *new_board(void)
  610. {
  611.   FD_board *fd_board;
  612.   int      seed;
  613.  
  614.   srand(time(0)); do {seed = rand();} while (!seed);
  615.   fd_board = create_form_board();
  616.   fl_xset_menu(fd_board->shanghai,"About...","Aa#A#a",NULL);
  617.   fl_xset_menu(fd_board->file,"New Game|Restart%l|Open Window|Close%l|Quit",
  618.            "Nn#N#n","Rr#R#r","Oo#O#o","Cc#C#c","Qq#Q#q\x1B",NULL);
  619.   fl_xset_menu(fd_board->options,"Undo|Pause%l|Fast moves","Uu#U#u","Pp#P#p",
  620.            "Ff#F#f",NULL);
  621.   initialize_board_rec(fd_board,NULL,seed);
  622.   fd_board->board_frame->objclass = FL_FREE;
  623.   fd_board->board_frame->type = FL_CONTINUOUS_FREE;
  624.   fd_board->board_frame->boxtype = 0;
  625.   fd_board->board_frame->handle = board_handle_free;
  626.   fd_board->board_frame->active = 1;
  627.   fd_board->board_frame->automatic = 1;
  628.   fd_board->status->objclass = FL_FREE;
  629.   fd_board->status->type = FL_INPUT_FREE;
  630.   fd_board->status->boxtype = 0;
  631.   fd_board->status->handle = status_handle_free;
  632.   fd_board->status->active = 1;
  633.   fd_board->status->automatic = 0;
  634.   win_count++;
  635.   fl_set_form_atclose(fd_board->board,board_close,NULL);
  636.   fl_set_form_minsize(fd_board->board,fd_board->board->w,fd_board->board->h);
  637.   fl_set_form_maxsize(fd_board->board,fd_board->board->w,fd_board->board->h);
  638.   rawcallback = fl_register_raw_callback(fd_board->board,FL_ALL_EVENT,
  639.                      focus_out);
  640.   fl_show_form(fd_board->board,FL_PLACE_FREE,FL_FULLBORDER,"Shanghai for X");
  641.    return(fd_board);
  642. }
  643.